#REXML
require "rexml/document"

#RubyTree
require 'rubygems'
require 'tree'

#Standard error message output
def error(msg = nil)
  if msg then
    puts "Error: #{msg}"
  else
    puts "Compare two files output by DxDiag"
    puts "Usage: test_output.rb file1 file2"
  end
  exit
end

#Given the current root, find if the value is in the tree
#Input: root node
#		Value
#Output: the node itself, or the root_node if none found
def findNode(root_node, value)
	root_node.breadth_each{|property|
		if property.name == value	
			return property
		end
	}
	return root_node
end

#Given the current root, find if the value is in the same tree branch
#Input: root node
#		Value
#Output: true / false
def nodeInTree(cur_node, value)
	cur_node.children{|property|
		if property.name == value
			return true
		end
	}
	return false
end
#given the current node, save a new node under it with Property value of linenumber and line
def saveNode(cur_node, linenumber, value)
	#ignore duplicates
	if !nodeInTree(cur_node, value)
		cur_node << Tree::TreeNode.new(value, linenumber)
	end
	#pass by reference
	cur_node
end

def checkXML(file1, file2)
	xml1 = File.read(file1)
	doc1 = REXML::Document.new xml1
	root1 = doc1.root
	
	xml2 = File.read(file2)
	doc2 = REXML::Document.new xml2
	root2 = doc2.root
	
	puts "Comparing #{file1} to see if its values are in #{file2}"
	
	linenumber = 0
	root1.elements.each('//*') do |p|
		linenumber +=1
	
		sameparents = false
		samename = false
		sametext = false

		root2.elements.each('//*') do |q|
			if  p.name.nil? or p.name == q.name
				samename = true
			end
			if  p.get_text.nil? or p.has_elements? or p.get_text == q.get_text 
				sametext = true
			end
			if  p.parent.name.nil? or p.parent.name == q.parent.name
				sameparents = true
			end
			
			if sameparents and samename and sametext
				break
			end	
		end
		if !samename or !sameparents or !sametext
			puts "Value: #{p.name}"
			puts "Line: #{linenumber}"
			puts "Differs!"
			puts "--------------------------------------\n"
		end
	end
end
#Gets all the properties of the file
#Input: File name
#Output: Hashtable of properties and values
#		 Hashtable of properties and linenumber
#		 Tree root of file hierachy
def get_raw_properties (file, format)

	#tree of relationships
	root_node = Tree::TreeNode.new("ROOT", "0")
	current_node = root_node
	#hash of properties
	prophash = Hash.new
	#hash of linenumbers
	linehash = Hash.new
	#counter for the line number of the property
	linenumber = 0
	#previous line
	prevline = ""
	if (format == '-t')
		newfile = File.open(file) do |f|
			while line = f.gets	
				linenumber +=1
				#is this line a property?
				unless line.include? ":"
					line.strip!	
					#is this line a header
					if !line.include? "-" and prevline.include? "--" and !line.include? "'" and !line.empty?
						root_node = saveNode(root_node, linenumber, line)
						#current node is the newly added node
						current_node = root_node[line]
					end	
					#increment previous line and move on to next line
					prevline = line
					next
				end
				#remove all spaces in the line
				property,value = line.split(/:/)
				property.strip!
				value.strip!
				#save the property
				prophash[property] = value
				#save the line number
				linehash[property] = linenumber
				#save the property in the tree			
				saveNode(current_node, linenumber, property)
				#increment previous line
				prevline = line
			end
		end
	end
	if (format == '-x')
		xml = File.read(file)
		doc = REXML::Document.new xml
		root = doc.root
		root.elements.each('//*') do |p|
			linenumber +=1
			cur_name = p.name
			linehash[cur_name] = linenumber
			if !p.has_elements?
				prophash[cur_name] = p.get_text
				#saveNode(current_node, linenumber, cur_name)
			else
				#parent_element = p.parent
				#finds the location of the node with the parent's name and add the current element underneth it
				#current_node = findNode(root_node, parent_element.name)
				#saveNode(current_node, linenumber, cur_name)
				#current_node = current_node[cur_name]
			end
		end
	end
	return prophash, linehash, root_node
end

#
#
#
#
#				Main Routine
#
#
#
#
#
winePropertyHash = Hash.new
wineLineHash = Hash.new

windowPropertyHash = Hash.new
windowLineHash = Hash.new

#print out arguements
if ARGV.size != 4
	error("Input need to be in the following Format: Ruby [Testing Executable] [-t or -x] [-both, -wine, -windows] [Wine File] [Windows File].  See the ReadME for more information")
	exit
end

check_parameter = ARGV[0]
comparison_direction = ARGV[1]
wine_path = ARGV[2]
window_path = ARGV[3]

if not File.readable? wine_path 
  error "input file #{wine_path} does not exist or is not readable"
end
if not File.readable? window_path
  error "input file #{window_path} does not exist or is not readable"
end

puts "Type of File: #{check_parameter}"
puts "Wine DxDaig File: #{wine_path}"
puts "Original DxDiag File: #{window_path}\n\n"


#create the hashes for the files
winePropertyHash, wineLineHash, wineRoot = get_raw_properties(wine_path, check_parameter)
windowPropertyHash, windowLineHash, windowRoot = get_raw_properties(window_path, check_parameter)

#property fields are exactly the same

if comparison_direction == '-wine' or comparison_direction == '-both'
	#compare new file from wine's properties to see if data is in old window's
	puts "\n-----------------------------------------------------------------------------------------"
	puts "Comparing New File #{wine_path} to see if the data is in the Old File #{window_path}\n"
	puts "-----------------------------------------------------------------------------------------\n"
	
	if check_parameter == '-t'
		wineRoot.breadth_each{|aNode|
		found = false
		windowRoot.breadth_each{|bNode|
			if (aNode.parent and bNode.parent)
				if aNode.parent.name == bNode.parent.name and aNode.name == bNode.name	
					found = true
					break
				end
			end
		}
		if (!found and aNode.parent)
			puts "The following was not found in Window's Hierachy"
			puts "Property: #{aNode.name}"		
			puts "Line: #{aNode.content}"		
			puts "Property's Attribute/Parent: #{aNode.parent.name}"
			puts "--------------------------------------\n"
		end
		}
		
		puts "\n-----------------------------------------------------------------------------------------"
		puts "---------------------------------------KEYS----------------------------------------------\n"
		puts "-----------------------------------------------------------------------------------------\n"
		
		winePropertyHash.each {|key, value|
			if windowPropertyHash[key] != value
				puts "Key: #{key}"
				puts "Value: #{value}"
				puts "Line: #{wineLineHash[key]}"
				puts "Window's Value is: #{windowPropertyHash[key]}"
				puts "Line: #{windowLineHash[key]}"
				puts "--------------------------------------\n"
			end
		}
	end
	if check_parameter == '-x'
		checkXML(wine_path, window_path)
	end
end

if comparison_direction == '-windows' or comparison_direction == '-both'
	#compare old file properties wine's to see if data is in new window's
	puts "\n-----------------------------------------------------------------------------------------"
	puts "Comparing Old File #{window_path} to see if the data is in the New File #{wine_path}\n"
	puts "-----------------------------------------------------------------------------------------\n"
	
	if check_parameter == '-t'
		windowRoot.breadth_each{|aNode|
		found = false
		wineRoot.breadth_each{|bNode|
			if (aNode.parent and bNode.parent)
				if aNode.parent.name == bNode.parent.name and aNode.name == bNode.name	
					found = true
					break
				end
			end
		}
		if (!found and aNode.parent)
			puts "The following was not found in Wine's Hierachy"
			puts "Property: #{aNode.name}"
			puts "Line: #{aNode.content}"
			puts "Parent: #{aNode.parent.name}"
			puts "--------------------------------------\n"
		end
		}
		
		puts "\n-----------------------------------------------------------------------------------------"
		puts "---------------------------------------KEYS----------------------------------------------\n"
		puts "-----------------------------------------------------------------------------------------\n"
		
		windowPropertyHash.each {|key, value|
			if winePropertyHash[key] != value
				puts "Key: #{key}"
				puts "Value: #{value}"
				puts "Line: #{windowLineHash[key]}"
				puts "Wine's Value is: #{winePropertyHash[key]}"
				puts "Line: #{wineLineHash[key]}"
				puts "--------------------------------------\n"
			end
		}
	end
	if check_parameter == '-x'
		checkXML(wine_path, window_path)
	end
end



